/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/container
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AETArray.h
// Author:		Gianluca Belardelli
// Date:		22/04/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AETARRAY_INL_
#define _AETARRAY_INL_


template <typename T, typename Allocator>
AE_FORCEINLINE AETArray<T,Allocator>::AETArray( const AETArray<T,Allocator> &refArray ) : AETBaseArray<T>()
{
	int nSize = refArray.GetSize();
	const int cnSize = nSize;
	AEMemoryAllocator &refAlloc = Allocator().Get(this);
	T *lpPtr = nSize ? refAlloc.TBufAlloc<T>( nSize ) : 0L;
	int nCapacity = nSize ? nSize : AETBaseArray<T>::DONT_DEALLOCATE_FLAG;
	AETBaseArray<T>::SetDataUnchecked( lpPtr, cnSize, nCapacity );
	AEArrayUtil::ConstructWithArray( lpPtr, cnSize, refArray.m_lpData, typename AEIsPodType<T>::type() );
}

template <typename T, typename Allocator>
AE_FORCEINLINE AETArray<T,Allocator>::~AETArray( void )
{
	ClearAndDeallocate();
}

template <typename T, typename Allocator>
AE_FORCEINLINE AETArray<T,Allocator>::AETArray( AEINT32 nSize )
{
	AEMemoryAllocator &refAlloc = Allocator().Get( this );
	const int cnSize = nSize;
	T *lpPtr = nSize ? refAlloc.TBufAlloc<T>( nSize ) : 0L;
	int nCapacity = cnSize ? cnSize : AETBaseArray<T>::DONT_DEALLOCATE_FLAG;
	AETBaseArray<T>::SetDataUnchecked( lpPtr, 0, nCapacity);
	AEArrayUtil::Construct( lpPtr, 0, typename AEIsPodType<T>::type());
}

template <typename T, typename Allocator>
AE_FORCEINLINE AETArray<T,Allocator>::AETArray( AEINT32 nSize, const T &tFill )
{
	AEMemoryAllocator &refAlloc = Allocator().Get( this );
	const int cnSize = nSize;
	T *lpPtr = nSize ? refAlloc.TBufAlloc<T>( nSize ) : 0L;
	int nCapacity = nSize ? nSize : AETBaseArray<T>::DONT_DEALLOCATE_FLAG;
	AETBaseArray<T>::SetDataUnchecked( lpPtr, cnSize, nCapacity);
	AEArrayUtil::ConstructWithCopy( lpPtr, cnSize, tFill, typename AEIsPodType<T>::type());
}

template <typename T, typename Allocator>
AE_FORCEINLINE AETArray<T,Allocator> &AETArray<T,Allocator>::operator= ( const AETBaseArray<T> &refArray )
{
	AETBaseArray<T>::_copyFromArray( Allocator().Get( this ), refArray, typename AEIsPodType<T>::type());
	return *this;
}

template <typename T, typename Allocator>
AE_FORCEINLINE AETArray<T,Allocator> &AETArray<T,Allocator>::operator= ( const AETArray &refArray )
{
	AETBaseArray<T>::_copyFromArray( Allocator().Get( this ), refArray, typename AEIsPodType<T>::type());
	return *this;
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::ClearAndDeallocate( void )
{
	AETBaseArray<T>::ClearAndDeallocate( AEAllocatorType().Get( this ) );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::OptimizeCapacity( AEINT32 nNumFreeElemsLeft, AEBOOL32 bShrinkExact )
{
	AETBaseArray<T>::OptimizeCapacity( 
			AEAllocatorType().Get( this ), nNumFreeElemsLeft, bShrinkExact
			);
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::PushBack( const T &tElem )
{
	AETBaseArray<T>::PushBack( AEAllocatorType().Get( this ), tElem );
}

template <typename T, typename Allocator>
AE_FORCEINLINE AEUINT32 AETArray<T,Allocator>::Reserve( AEINT32 nSize )
{
	return AETBaseArray<T>::Reserve( AEAllocatorType().Get( this ), nSize );
}

template <typename T, typename Allocator>
AE_FORCEINLINE AEUINT32 AETArray<T,Allocator>::ReserveExactly( AEINT32 nSize )
{
	return AETBaseArray<T>::ReserveExactly( AEAllocatorType().Get( this ), nSize );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::SetSize( AEINT32 nSize )
{
	AETBaseArray<T>::SetSize( AEAllocatorType().Get( this ), nSize );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::SetSize( AEINT32 nSize, const T &tFill )
{
	AETBaseArray<T>::SetSize( AEAllocatorType().Get( this ), nSize, tFill );
}

template <typename T, typename Allocator>
AE_FORCEINLINE AEUINT32 AETArray<T,Allocator>::TrySetSize( AEINT32 nSize )
{
	return AETBaseArray<T>::TrySetSize( AEAllocatorType().Get( this ), nSize );
}

template <typename T, typename Allocator>
AE_FORCEINLINE T &AETArray<T,Allocator>::ExpandOne( void )
{
	return AETBaseArray<T>::ExpandOne( AEAllocatorType().Get( this ) );
}

template <typename T, typename Allocator>
AE_FORCEINLINE T *AETArray<T,Allocator>::ExpandBy( AEINT32 nSize )
{
	return AETBaseArray<T>::ExpandBy( AEAllocatorType().Get( this ), nSize );
}

template <typename T, typename Allocator>
AE_FORCEINLINE T *AETArray<T,Allocator>::ExpandAt( AEINT32 nIndex, AEINT32 nNumToInsert )
{
	return AETBaseArray<T>::ExpandAt( AEAllocatorType().Get( this ), nIndex, nNumToInsert );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::InsertAt( AEINT32 nIndex, const T &tElem )
{
	AETBaseArray<T>::InsertAt( AEAllocatorType().Get( this ), nIndex, tElem );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::InsertAt( AEINT32 nIndex, const T *lpArray, AEINT32 nNumElems )
{
	AETBaseArray<T>::InsertAt( AEAllocatorType().Get( this ), nIndex, lpArray, nNumElems );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::Append( const T *lpArray, AEINT32 nNumElems )
{
	AETBaseArray<T>::Append( AEAllocatorType().Get( this ), lpArray, nNumElems );
}

template <typename T, typename Allocator>
AE_FORCEINLINE void AETArray<T,Allocator>::SpliceInto( AEINT32 nIndex, AEINT32 nDel, const T *lpArray, AEINT32 nNumElems )
{
	return AETBaseArray<T>::SpliceInto( 
			AEAllocatorType().Get( this ), nIndex, nDel, lpArray, nNumElems
			);
}		

template <typename T, typename Allocator>
void AETArray<T,Allocator>::Swap( AETArray &refArray )
{
	AEASSERT( 0 == ( AETBaseArray<T>::m_nCapacityAndFlags & AETBaseArray<T>::DONT_DEALLOCATE_FLAG ) || AETBaseArray<T>::m_lpData == 0L );
	AEASSERT( 0 == ( refArray.m_nCapacityAndFlags & AETBaseArray<T>::DONT_DEALLOCATE_FLAG ) || refArray.m_lpData == 0L );

	T *lpPtr = AETBaseArray<T>::m_lpData; // swap data
	AETBaseArray<T>::m_lpData = refArray.m_lpData;
	refArray.m_lpData = lpPtr;

	int nSize = AETBaseArray<T>::m_nSize; // swap size
	AETBaseArray<T>::m_nSize = refArray.m_nSize;
	refArray.m_nSize = nSize;

	int nCapacity = AETBaseArray<T>::m_nCapacityAndFlags; // swap cap
	AETBaseArray<T>::m_nCapacityAndFlags = refArray.m_nCapacityAndFlags;
	refArray.m_nCapacityAndFlags = nCapacity;
}

#endif // _AETARRAY_INL_